//
//  XMLUtil.m
//  XMLApp
//
//  Created by Nguyen .a.Hph on 3/4/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#import "XMLUtil.h"

@interface XMLUtil (Private)
+(void)removeNodes:(NSArray *)removeXPaths doc:(GDataXMLDocument *)doc;
+(void)removeNodes:(NSArray *)removeXPaths parentNode:(GDataXMLNode *)parentNode;

+(GDataXMLNode *)getParentChildContent:(GDataXMLNode *)parent child:(GDataXMLNode *)child isIncludeChild:(BOOL)isIncludeChild;
+(GDataXMLNode *)getChildParentContent:(GDataXMLNode *)child parent:(GDataXMLNode *)parent isIncludeChild:(BOOL)isIncludeChild;
+(GDataXMLNode *)getParentChildContent:(GDataXMLDocument *)doc parent:(NSString *)parentXPath child:(NSString *)childXPath isIncludeChild:(BOOL)isIncludeChild;
+(GDataXMLNode *)getChildParentContent:(GDataXMLDocument *)doc child:(NSString *)childXPath parent:(NSString *)parentXPath isIncludeChild:(BOOL)isIncludeChild;
+(BOOL)isParent:(GDataXMLNode *)parent child:(GDataXMLNode *)child;
+(NSString *)getContent:(GDataXMLDocument *)doc node1:(GDataXMLNode *)node1 isInclude1:(BOOL)isInclude1 isInner1:(BOOL)isInner1 node2:(GDataXMLNode *)node2 isInclude2:(BOOL)isInclude2 isInner2:(BOOL)isInner2 type:(int)type isInner:(BOOL)isInner removeXPath:(NSArray *)removeXPaths;

@end

@implementation XMLUtil

+(GDataXMLNode *)getContentFor:(NSString *)xpath doc:(GDataXMLDocument *)doc{
    NSError *error;
    NSArray *arr = [doc nodesForXPath:xpath error:&error];
    if (error){
        NSLog(@"%@", error);
        return nil;
    }
    if ([arr count]>0)
        return [arr objectAtIndex:0];
    return nil;
}

+(GDataXMLNode *)getContentFor:(NSString *)xpath removeXPath:(NSArray *)removeXPaths doc:(GDataXMLDocument *)doc{
    [self removeNodes:removeXPaths doc:doc];
    return [self getContentFor:xpath doc:doc];
}

+(GDataXMLNode *)getContentFor:(GDataXMLNode *)parentNode removeXPath:(NSArray *)removeXPaths{
    [self removeNodes:removeXPaths parentNode:parentNode];
    return parentNode;
}

+(NSString *)getContent:(GDataXMLDocument *)doc xpath1:(NSString *)xpath1 isInclude1:(BOOL)isInclude1 isInner1:(BOOL)isInner1 xpath2:(NSString *)xpath2 isInclude2:(BOOL)isInclude2 isInner2:(BOOL)isInner2 type:(int)type isInner:(BOOL)isInner removeXPath:(NSArray *)removeXPaths{
    [self removeNodes:removeXPaths doc:doc];
    if ([xpath1 length]==0)
        return @"";
    GDataXMLNode *node1 = [self getContentFor:xpath1 doc:doc];
    if (node1==nil)
        return [[doc rootElement] HTMLString];
    
    if ([xpath2 length]==0)
        return isInner1 ? [node1 innerHTML]:[node1 HTMLString];
    
    GDataXMLNode *node2 = [self getContentFor:xpath2 doc:doc];
    if (node2==nil)
        return isInner1 ? [node1 innerHTML]:[node1 HTMLString];
    
    return [self getContent:doc node1:node1 isInclude1:isInclude1 isInner1:isInner1 node2:node2 isInclude2:isInclude2 isInner2:isInner2 type:type isInner:isInner removeXPath:removeXPaths];
}

+(NSSet *)getDocumentSrc:(GDataXMLDocument *)doc{
    NSMutableSet *resultSet = [[NSMutableSet alloc] init];
    //image
    NSArray *imgSrcArr = [doc nodesForXPath:@"//*[@src]" error:nil];
    for(GDataXMLElement *node in imgSrcArr){
        NSString *value = [[node attributeForName:@"src"] stringValue];
        if ([value length]>3)
            [resultSet addObject:value];
    }
    //link
    NSArray *lnkSrcArr = [doc nodesForXPath:@"//*[@href]" error:nil];
    for(GDataXMLElement *node in lnkSrcArr){
        NSString *value = [[node attributeForName:@"href"] stringValue];
        if ([value length]>3)
            [resultSet addObject:value];
    }
    return resultSet;
}

//private
#pragma mark Private implementation

+(void)removeNodes:(NSArray *)removeXPaths doc:(GDataXMLDocument *)doc{
    NSError *error;
    for(NSString *xpath in removeXPaths){
        NSArray *arr = [doc nodesForXPath:xpath error:&error];
        if (error){
            NSLog(@"%@", error);
            continue;
        }
        for(GDataXMLNode *node in arr){
            GDataXMLNode *parent = [node parent];
            if (parent)
                [((GDataXMLElement *)parent) removeChild:node];
        }
    }
}

+(void)removeNodes:(NSArray *)removeXPaths parentNode:(GDataXMLNode *)parentNode{
    NSError *error;
    for(NSString *xpath in removeXPaths){
        NSArray *arr = [parentNode nodesForXPath:xpath error:&error];
        if (error){
            NSLog(@"%@", error);
            continue;
        }
        for(GDataXMLNode *node in arr){
            GDataXMLNode *parent = [node parent];
            if (parent)
                [((GDataXMLElement *)parent) removeChild:node];
        }
    }
}

+(GDataXMLNode *)getParentChildContent:(GDataXMLNode *)parent child:(GDataXMLNode *)child isIncludeChild:(BOOL)isIncludeChild{
    int count = 0;
    NSMutableArray *siblingArr = [[NSMutableArray alloc] init];
    GDataXMLNode *node;
    do {
        node = [child parent];
        GDataXMLNode *sibling = [child nextSibling];
        while (sibling!=nil) {
            [siblingArr addObject:sibling];
            sibling = [sibling nextSibling];
        }
        if (!isIncludeChild && count==0)
            [((GDataXMLElement *)node) removeChild:child];
        for(GDataXMLNode *n in siblingArr)
            [((GDataXMLElement *)node) removeChild:n];
        [siblingArr removeAllObjects];
        child = node;
        count++;
    } while (![[node HTMLString] isEqualToString: [parent HTMLString]]);
    return node;
}

+(GDataXMLNode *)getChildParentContent:(GDataXMLNode *)child parent:(GDataXMLNode *)parent isIncludeChild:(BOOL)isIncludeChild{
    int count = 0;
    NSMutableArray *siblingArr = [[NSMutableArray alloc] init];
    GDataXMLNode *node;
    do {
        node = [child parent];
        GDataXMLNode *sibling = [child previousSibling];
        while (sibling!=nil) {
            [siblingArr addObject:sibling];
            sibling = [sibling previousSibling];
        }
        if (!isIncludeChild && count==0)
            [((GDataXMLElement *)node) removeChild:child];
        for(GDataXMLNode *n in siblingArr)
            [((GDataXMLElement *)node) removeChild:n];
        [siblingArr removeAllObjects];
        child = node;
        count++;
    } while (![[node HTMLString] isEqualToString: [parent HTMLString]]);
    return node;
}

+(GDataXMLNode *)getParentChildContent:(GDataXMLDocument *)doc parent:(NSString *)parentXPath child:(NSString *)childXPath isIncludeChild:(BOOL)isIncludeChild{
    GDataXMLNode *parent = [self getContentFor:parentXPath doc:doc];
    GDataXMLNode *child = [self getContentFor:childXPath doc:doc];
    return [self getParentChildContent:parent child:child isIncludeChild:isIncludeChild];
}

+(GDataXMLNode *)getChildParentContent:(GDataXMLDocument *)doc child:(NSString *)childXPath parent:(NSString *)parentXPath isIncludeChild:(BOOL)isIncludeChild{
    GDataXMLNode *parent = [self getContentFor:parentXPath doc:doc];
    GDataXMLNode *child = [self getContentFor:childXPath doc:doc];
    return [self getChildParentContent:child parent:parent isIncludeChild:isIncludeChild];
}

+(BOOL)isParent:(GDataXMLNode *)parent child:(GDataXMLNode *)child{
    if ([[parent HTMLString] isEqualToString:[child HTMLString]])
        return YES;
    NSArray *arr = [parent children];
    for(GDataXMLNode *node in arr)
        if ([self isParent:node child:child])
            return YES;
    return NO;
}

+(NSString *)getContent:(GDataXMLDocument *)doc node1:(GDataXMLNode *)node1 isInclude1:(BOOL)isInclude1 isInner1:(BOOL)isInner1 node2:(GDataXMLNode *)node2 isInclude2:(BOOL)isInclude2 isInner2:(BOOL)isInner2 type:(int)type isInner:(BOOL)isInner removeXPath:(NSArray *)removeXPaths{
    [self removeNodes:removeXPaths doc:doc];
    NSMutableString *result = [[NSMutableString alloc] initWithString:@""];
    if (type==0){//same level
        if (isInclude1)
            [result appendString:(isInner1 ? [node1 innerHTML]:[node1 HTMLString])];
        GDataXMLNode *node = [node1 nextSibling];
        while (node!=nil && !([[node HTMLString] isEqualToString:[node2 HTMLString]])) {
            [result appendString:(isInner ? [node innerHTML]:[node HTMLString])];
            node = [node nextSibling];
        }
        if([[node HTMLString] isEqualToString:[node2 HTMLString]])
            if (isInclude2)
                [result appendString:(isInner2 ? [node2 innerHTML]:[node2 HTMLString])];
    } else if (type==-1){//node1 outer node 2
        if ([self isParent:node1 child:node2]){
            if (isInclude1){
                GDataXMLNode *tmpNode = [self getParentChildContent:node1 child:node2 isIncludeChild:isInclude2];
                [result appendString:(isInner1?[tmpNode innerHTML]:[tmpNode HTMLString])];
            }
        }
        else {
            if (isInclude1)
                [result appendString:(isInner1 ? [node1 innerHTML]:[node1 HTMLString])];
            GDataXMLNode *tmpNode = [node1 nextSibling];
            while (tmpNode!=nil && ![self isParent:tmpNode child:node2]) {
                [result appendString:(isInner ? [tmpNode innerHTML]:[tmpNode HTMLString])];
                tmpNode = [tmpNode nextSibling];
            }
            GDataXMLNode *tmpNode1 = [self getParentChildContent:tmpNode child:node2 isIncludeChild:isInclude2];
            [result appendString:(isInner ? [tmpNode1 innerHTML]:[tmpNode1 HTMLString])];
        }
    } else if (type==1){//node1 inner node2
        if ([self isParent:node2 child:node1]){
            if (isInclude2){
                GDataXMLNode *tmpNode = [self getChildParentContent:node1 parent:node2 isIncludeChild:isInclude1];
                [result appendString:(isInner2 ? [tmpNode innerHTML]:[tmpNode HTMLString])]; 
            }
        }
        else {
            NSString *st = @"";
            if (isInclude2)
                st = isInner2?[node2 innerHTML]:[node2 HTMLString];
            GDataXMLNode *tmpNode = [node2 previousSibling];
            while (tmpNode!=nil && ![self isParent:tmpNode child:node1]) {
                st = [[NSString alloc] initWithFormat:@"%@%@", (isInner?[tmpNode innerHTML]:[tmpNode HTMLString]),st];
                tmpNode = [tmpNode previousSibling];
            }
            GDataXMLNode *tmpNode1 = [self getChildParentContent:node1 parent:tmpNode isIncludeChild:isInclude1];
            st = [[NSString alloc] initWithFormat:@"%@%@", (isInner?[tmpNode1 innerHTML]:[tmpNode1 HTMLString]),st];
            [result appendString:st];
        }
    }
    return result;
}
//end private

@end


